import {recordEffectScope} from "./effectScope.js";

export let activeEffect = undefined;

function cleanupEffect(effect) {
    // {name:set(effect, effect)} 属性对应的 effect

    // 找到 deps 中的 set ,清理掉 effect 才可以
    let deps = effect.deps;
    for (let i = 0; i < deps.length; i++) {
        // effect.deps = [new Set(), new Set()]
        deps[i].delete(effect); // 删除掉 set 中的 effect
    }
    effect.deps.length = 0; // 让 effect 中的 deps 清空
}

export class ReactiveEffect {
    constructor(fn, scheduler) {
        this.fn = fn;
        this.parent = undefined;
        this.active = true
        this.deps = []; // effect 中要记录哪些属性是在 effect 中调用了
        this.scheduler = scheduler;
        recordEffectScope(this)
    }

    run() {
        // 当运行的时候，我们需要将对应的effect关联起来
        // 利用js时单线程的特性，先放在全局，再取值
        if (!this.active) {
            return this.fn()
        }
        try {
            this.parent = activeEffect;
            activeEffect = this;
            cleanupEffect(this);
            return this.fn(); // 执行函数时触发了属性的get
        } finally {
            activeEffect = this.parent;
            this.parent = undefined;
        }
    }

    stop() {
        if (this.active) {
            this.active = false
            cleanupEffect(this)
        }
    }
}

// 属性和 effect 之前是什么样的关系（n:n）依赖收集
// 1:1
// 1:n
// n:n √

export function effect(fn, options = {}) {
    // 将用户的函数变成一个响应式函数
    const _effect = new ReactiveEffect(fn, options.scheduler);
    // 默认让用户的函数执行一次
    _effect.run();
    const runner = _effect.run.bind(_effect);
    runner.effect = _effect;
    return runner;
}
